/*
**  Copyright (C), CHENGDU GONGWEI TECHNOLOGY CO.,LTD.
**
**  Project:	Manager Unit v1.0
**  File:    	
**  Author: 	zhaozhuyu
**  Date:    	2017/05/20
**
**  Purpose:
**    		.
**
**  History: 
**  <author>   <time>          <version >   <desc>
*	$$Author$$
*/


/* Include files. */

extern "C" { 
	#include "standard.h"
	#include "util.h"
	#include "debug.h"
} 

#include "ref.h"
#include "object.h"

/* Local function declarations. */

/* Macro API definitions. */

/* Global variable declarations. */

/* Type definitions. */

enum relateType {
	STRONG = 0,
	WEAK = 1,
};

/* Local function definitions. */
static int init_complete = false;
map<string, ref*> ref::ref_map_mgr;

ref* ref::findRef(string key)
{
	map<string, ref*>::iterator ite = ref_map_mgr.find(key);  
	if(ite != ref_map_mgr.end()){
		return ite->second;
	}
	else{
		return NULL;
	}  
}

int ref::add(ref *r)
{
	ref *r_ = findRef(r->_key);
	if (r_ == NULL) {
		ref_map_mgr[r->_key] = r;
		return true;
	}
	else {
		return false;
	}
}

int ref::remove(string key)
{
	ref *r = findRef(key);
	if (r != NULL) {
		ref_map_mgr.erase(key);
		delete r;
		return true;
	}
	else {
		return false;
	}
}

int luaRelate(lua_State* L)
{
	const char* dst  = lua_tostring(L, 1);
	const char* src  = lua_tostring(L, 2);
	const char* attr = lua_tostring(L, 3);
	int level = lua_tonumber(L, 4);
	if (init_complete == false) {
		ref *r = new ref(dst, src, attr, level);
		int ret = ref::add(r);
		if (ret == false) {
			delete r;
			goto faild;
		}
	}
	else {
		object *obj = object::findObject(dst);
		if (obj == NULL && level == WEAK) {
			ref *r = new ref(dst, src, attr, level);
			int ret = ref::add(r);
			if (ret == false) {
				delete r;
				goto faild;
			}
		}
		else if (obj == NULL && level == STRONG) {
			goto faild;
		}
		else {
			ref *r = new ref(dst, src, attr, level);
			int ret = obj->add(r);
			if (ret == false) {				
				delete r;
				goto faild;
			}
		}
	}
	lua_pushboolean(L, true);
	return 1;

faild:
	ERROR("%s.%s ralate %s faild!\n", src, attr, dst);
	lua_pushnil(L);
	return 1;
}

int luaUnRelate(lua_State* L)
{
	const char* dst  = lua_tostring(L, 1);
	const char* src  = lua_tostring(L, 2);
	const char* attr = lua_tostring(L, 3);
	if (init_complete == false) {
		string key = string(dst) + string(src) + string(attr);
		int ret = ref::remove(key);
		if (ret == false) {
			goto faild;
		}
	}
	else {
		object *obj = object::findObject(dst);
		if (obj == NULL ) {
			string key = string(dst) + string(src) + string(attr);
			int ret = ref::remove(key);
			if (ret == false) {
				goto faild;
			}
		}
		else {
			string key = string(src) + string(attr);
			int ret = obj->remove(key);
			if (ret == false) {
				goto faild;
			}
		}
	}
	lua_pushboolean(L, true);
	return 1;

faild:
	ERROR("%s.%s unralate %s faild!\n", src, attr, dst);
	lua_pushnil(L);
	return 1;
}

int luaRelateInit(lua_State* L)
{
	ref *r = NULL;
	map<string, ref*>::iterator iter;
	for(iter = ref::ref_map_mgr.begin(); iter != ref::ref_map_mgr.end();) {
		r = iter->second;
		object *obj = object::findObject(r->_dst);
		if (obj == NULL && r->_level == WEAK) {
			iter++;
			continue;
		}
		else if (obj == NULL && r->_level == STRONG) {
			ERROR("%s.%s ralate %s faild!\n", r->_src.c_str(), r->_attr.c_str(), r->_dst.c_str());
			delete r;
			goto faild;
		}
		else {
			int ret = obj->add(r);
			if (ret == false) {
				ERROR("%s.%s ralate %s faild!\n", r->_src.c_str(), r->_attr.c_str(), r->_dst.c_str());
				delete r;
				goto faild;
			}
			ref::ref_map_mgr.erase(iter++);
		}
	}
	init_complete = true;
	DEBUG("relate init success %d\n", ref::ref_map_mgr.size());
	lua_pushboolean(L, true);
	return 1;

faild:
	DEBUG("relate init faild %d\n", ref::ref_map_mgr.size());
	lua_pushnil(L);
	return 1;
}

